package com.googlecode.javaexamples.multithreading.ringbuffer;

import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;

public class RingBuffer<T> {
    private List<T> buffer;
    private int headIndex;		// Index of element which be returned by pop method
    private int elementCount;	// How many elements currently in the buffer
    private int capacity;		// Max elements which buffer can contain
    private static final int DEFAULT_CAPACITY = 10;

    public RingBuffer(int size) {
        if (size <= 0) throw new IllegalArgumentException();

        this.capacity = size;
        this.buffer = new ArrayList<T>(size);
    }

    public RingBuffer() {
        this(DEFAULT_CAPACITY);
    }

    private int wrapIndex(int index) {
        return (index % capacity);
    }

    // Pop item from the buffer
    public T pop() {
        if (elementCount <= 0) throw new NoSuchElementException();
        T result = null;
        result = buffer.get(headIndex);
        headIndex = wrapIndex(headIndex + 1);
        --elementCount;

        return result;
    }

    // Push item in the buffer.
    // In the case of overflow wrap index, if index equals headIndex increment headIndex and wrap
    public void push(T item) {
        int insertIndex = headIndex + elementCount;
        if (insertIndex >= capacity) {
            insertIndex = wrapIndex(insertIndex);
            buffer.set(insertIndex, item);
            if (insertIndex == headIndex) {
                headIndex = wrapIndex(headIndex + 1);
            }
        } else {
            buffer.add(insertIndex, item);
        }

        if (elementCount < capacity) {
            ++elementCount;
        }
    }

    // How many elements currently in the buffer
    public int elementCount() {
        return elementCount;
    }

    // Max elements which buffer can contain
    public int size() {
        return capacity;
    }
}
